package com.k.kc.util.thread;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author kivil
 */
public class ThreadUtils {
    private static ThreadPoolExecutor threadPool;
    private static final int DEFAULT_CORE_POOL_SIZE = 5;
    private static final int DEFAULT_MAXIMUM_POOL_SIZE = 10;
    private static final long DEFAULT_KEEP_ALIVE_TIME = 60;
    private static final TimeUnit DEFAULT_UNIT = TimeUnit.SECONDS;
    private static final int DEFAULT_CAPACITY = 32;
    private static final String DEFAULT_THREAD_NAME_PREFIX = "kpp-thread-";
    private static final int DEFAULT_THREAD_PRIORITY = 1;

    /**
     * 创建线程
     *
     * @param corePoolSize    核心线程
     * @param maximumPoolSize 最大线程
     * @param keepAliveTime   10(maximumPoolSize) -5(corePoolSize) = 5(新建的线程) 这 5个新建的线程 ,空闲时间(keepAliveTime),退出。
     * @param unit            keepAliveTime's Unit
     * @param workQueue       LinkedBlockingQueue
     * @param threadFactory   ThreadFactoryBuilder
     * @param handler         RejectedExecutionHandler
     * @return ExecutorService
     */
    public static ThreadPoolExecutor newThreadPoolE(int corePoolSize,
                                                    int maximumPoolSize,
                                                    long keepAliveTime,
                                                    TimeUnit unit,
                                                    BlockingQueue<Runnable> workQueue,
                                                    ThreadFactory threadFactory,
                                                    RejectedExecutionHandler handler) {
        return new ThreadPoolExecutor(
                // 核心线程
                corePoolSize,
                // 最大线程
                maximumPoolSize,
                // 10(maximumPoolSize) -5(corePoolSize) = 5(新建的线程) 这 5个新建的线程 ,空闲时间(keepAliveTime),退出。
                keepAliveTime, unit,
                workQueue,
                threadFactory,
                handler
        );
    }

    /**
     * @param corePoolSize     corePoolSize
     * @param maximumPoolSize  maximumPoolSize
     * @param keepAliveTime    keepAliveTime
     * @param unit             unit
     * @param capacity         capacity
     * @param threadNamePrefix threadNamePrefix
     * @param daemon           daemon
     * @param priority         priority
     * @return ExecutorService
     */
    public static ExecutorService newThreadPool(Integer corePoolSize,
                                                Integer maximumPoolSize,
                                                Integer keepAliveTime,
                                                TimeUnit unit,
                                                Integer capacity,
                                                String threadNamePrefix,
                                                Boolean daemon,
                                                Integer priority) {
        return newThreadPoolE(
                corePoolSize,
                maximumPoolSize,
                keepAliveTime, unit,
                new LinkedBlockingQueue<>(capacity),
                new ThreadFactoryBuilder().setNameFormat(threadNamePrefix).setDaemon(daemon).setPriority(priority).build(),
                new ThreadPoolExecutor.AbortPolicy()
        );
    }

    private static ThreadPoolExecutor newThreadPoolDefault() {
        return newThreadPoolE(
                DEFAULT_CORE_POOL_SIZE,
                DEFAULT_MAXIMUM_POOL_SIZE,
                DEFAULT_KEEP_ALIVE_TIME, DEFAULT_UNIT,
                new LinkedBlockingQueue<>(DEFAULT_CAPACITY),
                new ThreadFactoryBuilder().setNameFormat(DEFAULT_THREAD_NAME_PREFIX).setPriority(DEFAULT_THREAD_PRIORITY).build(),
                new ThreadPoolExecutor.AbortPolicy()
        );
    }

    private static ExecutorService getThreadPoolCache() {
        if (threadPool == null) {
            threadPool = newThreadPoolDefault();
            return threadPool;
        } else {
            if (!threadPool.isShutdown() && !threadPool.isTerminated() && !threadPool.isTerminating()) {
                threadPool = newThreadPoolDefault();
                return threadPool;
            }
        }
        try {
            TimeUnit.MILLISECONDS.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return getThreadPoolCache();
    }


    public static void main(String[] args) {
        System.out.println("Main start");
        ExecutorService executorService = ThreadUtils.newThreadPool(
                5,
                7,
                60,
                TimeUnit.SECONDS,
                32,
                "myThreadName-",
                false,
                1);
        // do something
//        List<CompletableFuture<String>> futureList = new ArrayList<>();
//        AtomicInteger atomicInteger = new AtomicInteger();
//        for(int i=0;i<12;i++){
//            executorService.execute(new Runnable() {
//                @Override
//                public void run() {
//                    System.out.println(Thread.currentThread().getId()+"@"+Thread.currentThread().getName()+" :run");
//                }
//            });
//            CompletableFuture<String> future = CompletableFuture.supplyAsync(()->{
//                return "com run"+atomicInteger.incrementAndGet();
//            },executorService);
//            futureList.add(future);
//        }
        executorService.shutdown();

        String str = null;
        System.out.println(Optional.ofNullable(str).isPresent());
        System.out.println(Optional.ofNullable(str).map(a->{
            return a;
        }).orElse("buweinull"));
        System.out.println(Optional.ofNullable(str).orElseGet(()-> {
            System.out.println("");
            return null;
        }));
    }
}
